#include <stdio.h>
#include <string.h>
#include <errno.h>

#define ARRAY_SIZE(x)		(sizeof(x)/sizeof(x[0]))	//宏定义：计算元素个数：数组字节数除以单个元素字节数，得数组元素数量

static inline void msleep(unsigned long ms);
static inline void print_usage(char *progname);
int socket_server_init(char *listen_ip, int listen_port);

int main(int argc, char **argv)
{
		int					listenfd, connfd;
		int					serv_port = 0;
		int					daemon_run = 0;
		char				*progname = NULL;
		int					opt;
		fd_set				rdset;
		int					rv;
		int					i, j;
		int					found;
		int					maxfd = 0;
		char				buf[1024];
		int					fds_array[1024];

		struct option		long_options[] =
		{
				{"daemon",no_argument, NULL, 'b'},
				{"port", required_argument, NULL, 'p'},
				{"help", no_argument, NULL, 'h'},
				{NULL, 0, NULL, 0}
		};

		progname = basename(argv[0]);	//取程序名

		//命令行参数解析
		while ((opt = getopt_long(argc, argv, "bp:h", long_options, NULL)) != -1)
		{
				switch(opt)
				{
						case 'b':
							daemon_run=1;
							break;
						case 'p':
							serv_port = atoi(optarg);	//将 serv_port 设置为从 optarg 转换来的整数值，表示服务器端口
							break;
						case 'h':
							print_usage(progname);
							return EXIT_SUCCESS;	// EXIT_SUCCESS 退出程序

						default:
							break;
				}
		}

		if( !serv_port )  //serv_port=0的情况下报错
		{
				print_usage(progname);
				return -1;
		}

		if( (listenfd=socket_server_init(NULL, serv_port)) < 0 )
		{
				printf("%s server listen on port %d failure: %s\n", argv[0], serv_port, strerror(errno));
				return -2;
		}
		printf("%s server start to listen on port %d\n", argv[0], serv_port);

		//创建后台
		if( daemon_run )
		{
				daemon(0, 0);
		}

		for(i=0; i<ARRAY_SIZE(fds_array); i++)
		{
				fds_array[i]=-1;
		}
		fds_array[0] = listenfd;

		for ( ; ; )
		{
				FD_SERO(&rdset);
				for(i=0; i<ARRAY_SIZE(fds_array); i++)
				{
						if(fds_array[i] < 0)
							continue;

						maxfd = fds_array[i]>maxfd?fds_array[i] : maxfd;
						FD_SET(fds_array[i], &rdset);
				}

				rv = select(macfd+1, &rdset, NULL, NULL, NULL);
				if(rv < 0)
				{
						printf("select failure: %s\n", strerror(errno));
						break;
				}
				else if(rv == 0)
				{
						printf("select get timeout\n");
						continue;
				}

				if( FD_ISSET(listenfd, &rdset) )
				{
						if( (connfd=accept(listenfd, (struct sockaddr *)NULL, NULL)) < 0 )
						{
								printf("accept new client failure: %s\n",strerror(errno));
								continue;
						}

						found = 0;
						for(i=0; i<ARRAY_SIZE(fds_array); i++)
						{
								if( fds_array[i] < 0 )
								{
										printf("accept new client[%d] and add it into array\n", connfd);
										fds_array[i] = connfd;
										found = 1;
										break;
								}
						}

						if( !found )
						{
								printf("accept new client[%d] but full, so refuse it\n", connfd);
								close(connfd);
						}
				}
				else
				{
						for(i=0; i<ARRAY_SIZE(fds_array); i++)
						{
								if( fds_array[i]<0 || !FD_ISSET(fds_array[i], &rdset) )
									continue；

								if( (rv=read(fds_array[i], buf, sizeof(buf))) <=0 )
								{
										printf("socket[%d] read failure or get disconnect.\n",fds_array[i]);
										close(fds_array);
										fds_array[i] = -1;
								}
								else
								{
										printf("socket[%d] read %d bytes data\n", fds_array[i], rv);

										for(j=0; j<rv; j++)
											buf[j]=toupper(buf[j]);

										if( write(fds_array[i], buf, rv) < 0 )
										{
												printf("socket[%d] write failure: %s\n", fds_array[i], strerror(errno));
												close(fds_array[i]);
												fds_array[i] = -1;
										}
								}
						}
				}
		}

CleanUp:
		close(listenfd);
		return 0;

}


static inline void msleep(unsigned long ms)
{
		struct timeval		tv;

		tv.tv_sec = ms/1000;		//秒
		tv.tv_usec = (ms%1000)*1000;		//微秒

		select(0, NULL, NULL, NULL, &tv);
}

static inline void print_usage(char *progname)
{
		printf("Usage: %S [OPTION]...\n", progname);

		printf("%s is a socket server program, which used to verify client ")
}

